
#include <BPhysics>
#include <BLabel>
#include <BImage>
#include <BIcon>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BHBoxLayout>
#include <BFileDialog>
#include <BColorDialog>
#include <BStyle>

#include "StringUtils.h"
#include "NodePanel.h"

NodePanel::NodePanel(BWidget* parent) : BGroupBox(parent)
{
	this->setTitle("Node");
	this->setFoldable(true);

	_node = 0;

	BHBoxLayout* topLayout = new BHBoxLayout();
	{
		_insertButton = new BButton();
		_insertButton->setTips("Insert a shape");
		_insertButton->setForm(Form_IconOnly);

		_physicsButton = new BButton();
		_physicsButton->setTips("Create physics");
		_physicsButton->setForm(Form_IconOnly);

		topLayout->addSpring();
		topLayout->addWidget(_insertButton);
		topLayout->addWidget(_physicsButton);
	}

	BGridLayout* gridLayout = new BGridLayout();
	{
		BLabel* visibleLabel = new BLabel("Visible");
		_visibleCheckBox = new BCheckBox();

		BLabel* optimizedLabel = new BLabel("Optimized");
		_optimizedCheckBox = new BCheckBox();

		gridLayout->setWidget(0, 0, visibleLabel);
		gridLayout->setWidget(0, 1, _visibleCheckBox);
		gridLayout->setWidget(1, 0, optimizedLabel);
		gridLayout->setWidget(1, 1, _optimizedCheckBox);
		gridLayout->setSpacing(3);
		gridLayout->setColumnPolicy(0, Policy_Preferred);
	}

	_physicsGroupBox = new BGroupBox("Physics");
	_physicsGroupBox->setFoldable(true);
	_physicsGroupBox->setFlat(true);
	_physicsGroupBox->setPerch(0, -1, 0, 0);
	_physicsGroupBox->setBorder(0);
	{
		BLabel* nameLabel = new BLabel("Name");
		_nameEdit = new BLineEdit();

		BLabel* massLabel = new BLabel("Mass");
		_massSpinBox = new BRealSpinBox();

		BLabel* gravityLabel = new BLabel("Gravity");
		_gravityEdit = new BLineEdit();

		BLabel* frictionLabel = new BLabel("Friction");
		_frictionSpinBox = new BRealSpinBox();

		BLabel* elastaneLabel = new BLabel("Elastane");
		_elastaneSpinBox = new BRealSpinBox();

		BLabel* forceLabel = new BLabel("Force");
		_forceEdit = new BLineEdit();

		BLabel* velocityLabel = new BLabel("Velocity");
		_velocityEdit = new BLineEdit();

		BLabel* rotationLabel = new BLabel("Rotation");
		_rotationEdit = new BLineEdit();

		BGridLayout* gridLayout = new BGridLayout(_physicsGroupBox);
		gridLayout->setWidget(0, 0, nameLabel);
		gridLayout->setWidget(0, 1, _nameEdit);
		gridLayout->setWidget(1, 0, massLabel);
		gridLayout->setWidget(1, 1, _massSpinBox);
		gridLayout->setWidget(2, 0, gravityLabel);
		gridLayout->setWidget(2, 1, _gravityEdit);
		gridLayout->setWidget(3, 0, frictionLabel);
		gridLayout->setWidget(3, 1, _frictionSpinBox);
		gridLayout->setWidget(4, 0, elastaneLabel);
		gridLayout->setWidget(4, 1, _elastaneSpinBox);
		gridLayout->setWidget(5, 0, forceLabel);
		gridLayout->setWidget(5, 1, _forceEdit);
		gridLayout->setWidget(6, 0, velocityLabel);
		gridLayout->setWidget(6, 1, _velocityEdit);
		gridLayout->setWidget(7, 0, rotationLabel);
		gridLayout->setWidget(7, 1, _rotationEdit);
		gridLayout->setColumnStretch(1, 100);
		gridLayout->setSpacing(3);
	}

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addLayout(topLayout);
	vlayout->addLayout(gridLayout);
	vlayout->addWidget(_physicsGroupBox);

	connect(this, Signal_AssetChanged, &NodePanel::slotAssetChanged);
	connect(_physicsButton, Signal_Clicked, &NodePanel::slotPhysicsButtonClicked);
	connect(_physicsButton, Signal_AssetChanged, &NodePanel::slotPhysicsButtonAssetChanged);

	connect(_visibleCheckBox, Signal_Toggled, &NodePanel::slotVisibleToggled);
	connect(_optimizedCheckBox, Signal_Toggled, &NodePanel::slotOptimizedToggled);

	connect(_nameEdit, Signal_EditFinished, &NodePanel::slotNameEdited);
	connect(_massSpinBox, Signal_EditFinished, &NodePanel::slotMassEditFinished);
	connect(_gravityEdit, Signal_EditFinished, &NodePanel::slotGravityEditFinished);
	connect(_frictionSpinBox, Signal_EditFinished, &NodePanel::slotFrictionEditFinished);
	connect(_elastaneSpinBox, Signal_EditFinished, &NodePanel::slotElastanceEditFinished);
	connect(_forceEdit, Signal_EditFinished, &NodePanel::slotForceEditFinished);
	connect(_velocityEdit, Signal_EditFinished, &NodePanel::slotVelocityEditFinished);
	connect(_rotationEdit, Signal_EditFinished, &NodePanel::slotRotationEditFinished);

}
NodePanel::~NodePanel()
{

}

void NodePanel::freshPhysics()
{
	if (BPhysics* physics = _node->physics())
	{
		_physicsButton->setAsset(physics);
		_physicsGroupBox->show();
		_nameEdit->setText(physics->name());
		_massSpinBox->setValue(physics->mass());
		_gravityEdit->setText(StringFromVector(physics->gravity()));
		_frictionSpinBox->setValue(physics->friction());
		_elastaneSpinBox->setValue(physics->elastane());
		_forceEdit->setText(StringFromVector(physics->force()));
		_velocityEdit->setText(StringFromVector(physics->velocity()));
		_rotationEdit->setText(StringFromVector(physics->rotation()));
	}
	else
	{
		_physicsButton->setAsset(BValue());
		_physicsGroupBox->hide();
	}
}

void NodePanel::slotAssetChanged()
{
	_node = this->asset();
	if (_node)
	{
		_visibleCheckBox->setChecked(_node->visible());
		_optimizedCheckBox->setChecked(_node->optimized());
		freshPhysics();
	}
}
void NodePanel::slotPhysicsButtonClicked(BObject* object)
{
	if (BPhysics* physics = object->asset())
	{
		_node->setPhysics(0);
		object->setAsset(0);
	}
	else
	{
		physics = new BPhysics();
		_node->setPhysics(physics);
		object->setAsset(physics);
	}
	freshPhysics();
}
void NodePanel::slotPhysicsButtonAssetChanged(BObject* object)
{
	if (BPhysics* physics = object->asset())
		_physicsButton->setTips("Remove physics");
	else
		_physicsButton->setTips("Create physics");
}
void NodePanel::slotVisibleToggled(BObject* object, const BValue& value)
{
	bool visible = value;
	_node->setVisible(visible);
}
void NodePanel::slotOptimizedToggled(BObject* object, const BValue& value)
{
	bool optimized = value;
	_node->setOptimized(optimized);
}

void NodePanel::slotNameEdited(BObject* object, const BValue& value)
{
	if (BPhysics* physics = _node->physics())
	{
		const BString& name = value;
		physics->setName(name);
	}
}
void NodePanel::slotMassEditFinished(BObject* object, const BValue& value)
{
	if (BPhysics* physics = _node->physics())
	{
		BReal mass = value;
		physics->setMass(mass);
	}
}
void NodePanel::slotGravityEditFinished(BObject* object, const BValue& value)
{
	const BString& text = value;
	BVector gravity = StringToVector(text);
	if (BPhysics* physics = _node->physics())
	{
		physics->setGravity(gravity);
	}
}
void NodePanel::slotFrictionEditFinished(BObject* object, const BValue& value)
{
	if (BPhysics* physics = _node->physics())
	{
		BReal friction = value;
		physics->setFriction(friction);
	}
}
void NodePanel::slotElastanceEditFinished(BObject* object, const BValue& value)
{
	if (BPhysics* physics = _node->physics())
	{
		BReal elastance = value;
		physics->setElastane(elastance);
	}
}
void NodePanel::slotForceEditFinished(BObject* object, const BValue& value)
{
	const BString& text = value;
	if (BPhysics* physics = _node->physics())
	{
		BVector force = StringToVector(text);
		physics->setForce(force);
	}
}
void NodePanel::slotVelocityEditFinished(BObject* object, const BValue& value)
{
	const BString& text = value;
	if (BPhysics* physics = _node->physics())
	{
		BVector velocity = StringToVector(text);
		physics->setVelocity(velocity);
	}
}
void NodePanel::slotRotationEditFinished(BObject* object, const BValue& value)
{
	const BString& text = value;
	if (BPhysics* physics = _node->physics())
	{
		BVector rotation = StringToVector(text);
		physics->setRotation(rotation);
	}
}

void NodePanel::styleEvent(const BEvent& event)
{
	BGroupBox::styleEvent(event);
	if (const BStyle* style = this->realStyle())
	{
		_insertButton->setIcon(style->icon("insert"));
		_physicsButton->setIcon(style->icon("physics"));
	}
}
